#include <stdio.h>  // for printf
#include <string.h> // for memory operation
#include <stdlib.h>
#include <unistd.h> // for sleep
#include "ohos_init.h"
#include "cmsis_os2.h"

#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "wifi_error_code.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "iot_uart.h"
#include "WifiSta.h"

#include "MQTTClient.h"
#include "cJSON.h"
#define SSID "Nice"
#define KEY "12312312"
#define ZB_UART_BAUDRATE 9600
#define ZB_UART_IDX_1 1
#define TCP_PORT 5552
#define TCP_BACKLOG 8
#define TCP_NUM 2 // 最多3个超了无法accept a envi b esp32 c smoke
#define OPEN "287"
#define MOTOR_DIR1 "297"
#define MOTOR_DIR2 "2A7"

#define HOST_ADDR "baaeb697c9.st1.iotda-device.cn-north-4.myhuaweicloud.com"
#define SERVICE_ID "Agri1"
#define DEVICE_ID "67347199fc8d5a4ea723e968_Agri1_0_0_2024111413"
#define DEVICE_USER "67347199fc8d5a4ea723e968_Agri1"
#define DEVICE_PWD "d3943c75a527d8ca9ee7300f7f225a09225eb374981015eb166d08c9d29fa352"
#define TOPIC_PUBLISH "$oc/devices/" DEVICE_USER "/sys/properties/report"
#define TPOIC_SUBCRIB "$oc/devices/" DEVICE_USER "/sys/commands/#"
#define TOPIC_RESPONSE "$oc/devices/" DEVICE_USER "/sys/commands/response/"

#define ledOn "ON"
static char recvbuf[512] = {0};
static char uart_buff[512] = {0};
static unsigned char send_mqttBuf[1000];
static unsigned char recv_mqttBuf[1000];

char temp_str[20] = {0}, humi_str[20] = {0}, light_str[20] = {0}, led_str[20] = {0}, ohumi_str[20] = {0}, co2_str[20] = {0}, auto_str[20] = {0}, fan_str[20] = {0};
float temp, humi, light, ohumi, co2;
MQTTClient client;
Network network;

int sock_fd = 0, flag = 0, music, id_flag, ERROR, Led, Auto, Fan;
int fd[8];
int GatewayUartTask();
void TCPServerTask(void);
void MqttTask(void);
void Find(int type, char *str);
int GatewayUartInit(void);
void messageHandle(MessageData *data);
void message_Cmdback(char *data);
static void TCPServerDemo(void)
{
    osThreadAttr_t attr;

    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 10;
    attr.priority = osPriorityNormal;
    attr.name = "GatewayUartTask";
    osThreadNew((osThreadFunc_t)GatewayUartTask, NULL, &attr);
    printf("success to create GatewayUartTask!\r\n");
    attr.name = "MqttTask";
    osThreadNew((osThreadFunc_t)MqttTask, NULL, &attr);
    attr.name = "TCPTask";
    osThreadNew((osThreadFunc_t)TCPServerTask, NULL, &attr);
    printf("success to create TCPServerTask!\r\n");
}

int GatewayUartTask()
{
    int ret = 0;

    GatewayUartInit(); // UART初始化
    osDelay(400);

    // 等待TCP客户端连接，才转发数据
    while (fd[TCP_NUM - 1] == 0)
    {
        osDelay(100);
    }
    int gateCount;
    while (1)
    {
        memset_s(uart_buff, sizeof(uart_buff), 0, sizeof(uart_buff));
        // 通过串口1接收数据
        ret = IoTUartRead(ZB_UART_IDX_1, uart_buff, sizeof(uart_buff));

        usleep(100);
    }
    return 0;
}
void TCPServerTask(void)
{
    // 服务端地址信息
    struct sockaddr_in server_sock;

    // 客户端地址信息
    struct sockaddr_in client_sock;
    int sin_size;

    // 连接Wifi
    WifiConnect(SSID, KEY);

    // 创建socket
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("socket is error\r\n");
        exit(1);
    }

    // 绑定IP地址等参数
    bzero(&server_sock, sizeof(server_sock));
    server_sock.sin_family = AF_INET;
    server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
    server_sock.sin_port = htons(TCP_PORT);

    // 调用bind函数绑定socket和地址
    if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
    {
        printf("bind is error\r\n");
        exit(1);
    }

    // 调用listen函数监听(指定port监听)
    if (listen(sock_fd, TCP_BACKLOG) == -1)
    {
        printf("listen is error\r\n");
        exit(1);
    }

    printf("start accept\r\n");
    int i = 0;
    // 调用accept函数接受客户端连接请求
    while (1)
    {
        if (i > TCP_NUM - 1)
            i = 0;
        sin_size = sizeof(struct sockaddr_in);
        printf("wait accept.\r\n");
        if ((fd[i]  = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
        {
            printf("accept");
            continue;
        }

        printf("accept addr\r\n");
        i++;
        printf("%d\n", i);
        // 处理目标
        int j = 0;
        uint32_t a, b, c;
        ssize_t ret;
        while (i > TCP_NUM - 1) // 数量判断成功后开始接收
        {
            if (j > i - 1)
            {
                j = 0;
            }
            memset_s(recvbuf, sizeof(recvbuf), 0, sizeof(recvbuf));
            if ((ret = recv(fd[j], recvbuf, sizeof(recvbuf), 0)) == -1)
            {
                printf("recv error \r\n");
            }
            else
            {
                printf("recv :%s\r\n", recvbuf);
            }

            if (strstr(recvbuf, "A") != NULL)
            {
                strncpy(temp_str, recvbuf + 1, 9);
                strncpy(humi_str, recvbuf + 11, 9);
                strncpy(light_str, recvbuf + 21, 9);
                strncpy(led_str, recvbuf + 31, 1);
                strncpy(fan_str, recvbuf + 33, 2);
                sscanf(temp_str, "%f", &temp);
                sscanf(humi_str, "%f", &humi);
                sscanf(light_str, "%f", &light);
                sscanf(led_str, "%d", &Led);
                sscanf(fan_str, "%d", &Fan);
            }
            else
                printf("NULL\n");

            if (strstr(recvbuf, "B") != NULL)
            {

                strncpy(ohumi_str, recvbuf + 1, 2);
                strncpy(co2_str, recvbuf + 4, 4);
                sscanf(ohumi_str, "%f", &ohumi);
                sscanf(co2_str, "%f", &co2);
                flag = 1; // 标志接受完成
            }
            else
                printf("NULL\n");

            j++;
            usleep(1000);
        }

        // close(new_fd);
        usleep(100);
    }
}
void MqttTask(void)
{
    sleep(4);
    NetworkInit(&network);
    printf("NetworkInit\n");
begin:
    NetworkConnect(&network, HOST_ADDR, 1883);
    printf("MqttClinetInit\n");
    MQTTClientInit(&client, &network, 2000, send_mqttBuf, sizeof(send_mqttBuf), recv_mqttBuf, sizeof(recv_mqttBuf));
    // 配置平台端MQTT连接
    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = DEVICE_ID;
    MQTTString clientUser = MQTTString_initializer;
    clientUser.cstring = DEVICE_USER;
    MQTTString clientPwd = MQTTString_initializer;
    clientPwd.cstring = DEVICE_PWD;
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID = clientId;
    data.username = clientUser;
    data.password = clientPwd;
    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;
    printf("MQTTConect\n");
    int rc = MQTTConnect(&client, &data);
    if (rc != 0)
    {
        printf("MQTTConect %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        sleep(2);
        goto begin;
    }
    // 配置订阅指令
    printf("MQTTSUBCRIBE\n");
    rc = MQTTSubscribe(&client, TPOIC_SUBCRIB, 0, messageHandle);
    if (rc != 0)
    {
        printf("MQTTSubscribe %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        sleep(2);
        goto begin;
    }

    while (1)
    {
        if (flag == 1)
        {
            printf("===mqtt send\n");
            MQTTMessage message;
            char payload[100] = {0};
            cJSON *root = cJSON_CreateObject();
            if (root != NULL)
            {
                cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");
                cJSON *arr_item = cJSON_CreateObject();
                cJSON_AddStringToObject(arr_item, "service_id", SERVICE_ID);
                cJSON *pro_obj = cJSON_CreateObject();
                cJSON_AddItemToObject(arr_item, "properties", pro_obj);

                // JSON拼接
                cJSON_AddNumberToObject(pro_obj, "Temp", temp);
                cJSON_AddNumberToObject(pro_obj, "Humi", humi);
                cJSON_AddNumberToObject(pro_obj, "Light", light);
                cJSON_AddNumberToObject(pro_obj, "Ohumi", ohumi);
                cJSON_AddNumberToObject(pro_obj, "Co2", co2);
                if (Led == 1)
                    cJSON_AddStringToObject(pro_obj, "Led", "ON");
                else
                    cJSON_AddStringToObject(pro_obj, "Led", "OFF");
                if (Auto == 1)
                    cJSON_AddStringToObject(pro_obj, "Auto", "auto");
                else
                    cJSON_AddStringToObject(pro_obj, "Auto", "man");

                cJSON_AddNumberToObject(pro_obj, "Fan", Fan);
                if (ERROR == 1)
                    cJSON_AddStringToObject(pro_obj, "Error", "ON");
                music = 0; // 复位
                // sprintf(music_str,"%d",music);
                cJSON_AddItemToArray(serv_arr, arr_item);
                char *play_str = cJSON_PrintUnformatted(root);
                strcpy(payload, play_str);
                cJSON_free(play_str);
                cJSON_Delete(root);
            }
            message.qos = 0;
            message.retained = 0;
            message.payload = payload;
            message.payloadlen = strlen(payload);
            if ((rc = MQTTPublish(&client, TOPIC_PUBLISH, &message)) != 0)
            {
                printf("MQTT Publish Failed\n");
                NetworkDisconnect(&network);
                MQTTDisconnect(&client);
                sleep(2);
                goto begin;
            }
            else
            {
                printf("mqtt publish success:%s\n", payload);
            }
            flag = 0;
        }
        MQTTYield(&client, 2000);
    }
}
int GatewayUartInit(void)
{

    uint32_t ret;
    IotUartAttribute uart_attr = {

        // baud_rate: 9600
        .baudRate = ZB_UART_BAUDRATE,

        // data_bits: 8bits
        .dataBits = 8,
        .stopBits = 1,
        .parity = 0,
    };

    // Initialize uart driver
    ret = IoTUartInit(ZB_UART_IDX_1, &uart_attr);
    if (ret != 0)
    {
        printf("Failed to init uart! Err code = %d\r\n", ret);
        return;
    }
    printf("UART Test Start\r\n");
}
void Find(int index, char *str)
{ // 注意形参格式
    int ret;

    printf("str == %s\n", str);
    if ((ret = send(fd[index - 1], str, strlen(str) + 1, 0)) == -1)
    {
        printf("send failed! \r\n");
    }
    else
    {
        printf("transfer to TCP client \r\n");
    }
}

void messageHandle(MessageData *data)
{
    printf("messeage on topic:%s,data%s\n", data->topicName->lenstring.data, data->message->payload);
    char *request_id_idx = NULL;
    request_id_idx = strstr(data->topicName->lenstring.data, "request_id=");
    char request_id[50] = {0};
    strncpy(request_id, request_id_idx + 11, 36);
    cJSON *root = cJSON_ParseWithLength(data->message->payload, data->message->payloadlen);
    if (root != NULL)
    {
        cJSON *cmd_name = cJSON_GetObjectItem(root, "command_name");
        if (cmd_name != NULL)
        {
            char *cmd_name_str = cJSON_GetStringValue(cmd_name);

            if (strcmp(cmd_name_str, "auto") == 0)
            {
                cJSON *para_obj = cJSON_GetObjectItem(root, "paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj, "auto");
                char *auto_str = cJSON_GetStringValue(status_obj);
                if (auto_str != NULL)
                    Find(2, auto_str); // 给1号发送auto_str内容
                cJSON_free(auto_str);
            }

            if (strcmp(cmd_name_str, "Led") == 0)
            {
                cJSON *para_obj = cJSON_GetObjectItem(root, "paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj, "Led");
                char *led_str = cJSON_GetStringValue(status_obj);
                if (led_str != NULL)
                    Find(2, led_str); // 给1号发送Led_str内容

                Find(2, "man");
                cJSON_free(led_str);
            }
            if (strcmp(cmd_name_str, "Fan") == 0)
            {
                cJSON *para_obj = cJSON_GetObjectItem(root, "paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj, "Fan");
                float fan = cJSON_GetNumberValue(status_obj);
                if (fan != 0)
                {
                    sprintf(fan_str, "%d", (unsigned short)fan);
                    strcat(fan_str, "Fan");
                    Find(2, fan_str); // 给1号发送fan_str内容
                }
                Find(2, "man");
            }

            if (strcmp(cmd_name_str, "Motor") == 0)
            {
                cJSON *para_obj = cJSON_GetObjectItem(root, "paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj, "Motor");
                char *motor_str = cJSON_GetStringValue(status_obj);
                if (motor_str != NULL)
                {
                    if (strcmp(motor_str, "le") == 0)
                    {
                        IoTUartWrite(ZB_UART_IDX_1, MOTOR_DIR2, strlen(MOTOR_DIR2));
                    }
                    else if (strcmp(motor_str, "ri") == 0)
                    {
                        IoTUartWrite(ZB_UART_IDX_1, MOTOR_DIR1, strlen(MOTOR_DIR1));
                    }
                }
                Find(2, "man");
                cJSON_free(motor_str);
            }

            if (strcmp(cmd_name_str, "Pump") == 0)
            { 
                cJSON *para_obj = cJSON_GetObjectItem(root, "paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj, "Pump");
                char *pump_str = cJSON_GetStringValue(status_obj);
                if (pump_str != NULL)
                    Find(1, pump_str); // 给1号发送pump_str内容
                Find(2, "man");
                cJSON_free(pump_str);
            }
        }
        message_Cmdback(request_id);
        cJSON_Delete(root);
    }
}

// 指令返回
void message_Cmdback(char *data)
{
    char retopic_str[128] = {0};
    sprintf(retopic_str, "%srequest_id=%s", TOPIC_RESPONSE, data);
    printf("retopic = %s\n", retopic_str);
    MQTTMessage message;
    char payload[200] = {0};
    message.qos = 0;
    message.retained = 0;
    sprintf(payload, "{\
    \"result_code\": 0,\
    \"response_name\": \"COMMAND_RESPONSE\",\
    \"paras\": {\
        \"result\": \"success\"\
    }\
    }");
    message.payload = payload;
    message.payloadlen = strlen(payload);
    int rc;
    if ((rc = MQTTPublish(&client, retopic_str, &message)) != 0)
    {
        printf("MessageCmdback Publish Failed\n");
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        sleep(2);
    }
    else
    {
        printf("MessageCmdback publish success:%s\n", payload);
    }
}
APP_FEATURE_INIT(TCPServerDemo);